package com.example.controller;

import com.example.annotation.AuditLog;
import com.example.annotation.RateLimit;
import com.example.exception.BusinessException;
import com.example.model.Payment;
import com.example.service.PaymentService;
import com.example.util.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * 安全支付控制器
 */
@Slf4j
@RestController
@RequestMapping("/api/payments")
@Tag(name = "支付管理", description = "安全的支付接口")
@RequiredArgsConstructor
public class PaymentController {

    private final PaymentService paymentService;
    private final SecurityUtils securityUtils;

    @PostMapping("/create")
    @Operation(summary = "创建支付订单")
    @RateLimit(key = "create_payment", type = RateLimit.LimitType.USER, limit = 10, window = 3600, 
               message = "支付创建过于频繁")
    @AuditLog(operation = com.example.model.AuditLog.OperationType.CREATE, 
              module = "PAYMENT", description = "创建支付订单", 
              riskLevel = com.example.model.AuditLog.RiskLevel.HIGH)
    public ResponseEntity<Map<String, Object>> createPayment(
            @Valid @RequestBody CreatePaymentRequest request,
            HttpServletRequest httpRequest,
            Authentication authentication) {

        try {
            // 输入验证
            validateCreatePaymentRequest(request);
            
            // 获取客户端信息
            String clientIp = getClientIp(httpRequest);
            String userAgent = httpRequest.getHeader("User-Agent");
            
            // 创建支付
            Payment payment = paymentService.createPayment(
                request.getOrderId(),
                request.getPaymentMethod(),
                clientIp,
                userAgent
            );

            // 构建响应
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("message", "支付订单创建成功");
            response.put("data", Map.of(
                "paymentNo", payment.getPaymentNo(),
                "paymentUrl", payment.getPaymentUrl() != null ? payment.getPaymentUrl() : "",
                "qrCode", payment.getQrCode() != null ? payment.getQrCode() : "",
                "amount", payment.getAmount(),
                "expireTime", payment.getExpireTime(),
                "status", payment.getStatus()
            ));

            return ResponseEntity.ok(response);

        } catch (BusinessException e) {
            log.warn("创建支付失败: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("创建支付异常: {}", e.getMessage(), e);
            throw new BusinessException("PAYMENT_CREATE_ERROR", "创建支付失败");
        }
    }

    @GetMapping("/{paymentNo}")
    @Operation(summary = "查询支付状态")
    @RateLimit(key = "query_payment", type = RateLimit.LimitType.USER, limit = 60, window = 3600)
    public ResponseEntity<Map<String, Object>> getPaymentStatus(
            @PathVariable @NotBlank String paymentNo,
            Authentication authentication) {

        try {
            // 输入验证
            if (!securityUtils.isSafeFilename(paymentNo)) {
                throw new BusinessException("INVALID_PAYMENT_NO", "支付单号格式错误");
            }

            Payment payment = paymentService.getPaymentByNo(paymentNo);
            
            // 权限检查 - 只能查询自己的支付记录
            String currentUserId = authentication.getName();
            if (!payment.getUserId().equals(currentUserId)) {
                throw new BusinessException("ACCESS_DENIED", "无权限访问该支付记录");
            }

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("data", Map.of(
                "paymentNo", payment.getPaymentNo(),
                "orderId", payment.getOrderId(),
                "amount", payment.getAmount(),
                "status", payment.getStatus(),
                "paymentMethod", payment.getPaymentMethod(),
                "createdAt", payment.getCreatedAt(),
                "paidAt", payment.getPaidAt(),
                "expireTime", payment.getExpireTime()
            ));

            return ResponseEntity.ok(response);

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("查询支付状态异常: {}", e.getMessage(), e);
            throw new BusinessException("PAYMENT_QUERY_ERROR", "查询支付状态失败");
        }
    }

    @PostMapping("/callback/{channel}")
    @Operation(summary = "支付回调接口")
    @RateLimit(key = "payment_callback", type = RateLimit.LimitType.IP, limit = 100, window = 3600)
    public ResponseEntity<String> paymentCallback(
            @PathVariable String channel,
            @RequestBody String notifyContent,
            HttpServletRequest request) {

        try {
            log.info("收到支付回调: channel={}, ip={}", channel, getClientIp(request));
            
            // 验证回调来源IP（实际应用中应该验证支付平台的IP白名单）
            String clientIp = getClientIp(request);
            if (!isValidCallbackIp(clientIp, channel)) {
                log.warn("非法回调IP: channel={}, ip={}", channel, clientIp);
                return ResponseEntity.badRequest().body("INVALID_IP");
            }

            // 解析回调内容（这里应该根据具体支付渠道解析）
            Map<String, String> callbackData = parseCallbackContent(notifyContent, channel);
            
            String paymentNo = callbackData.get("paymentNo");
            String thirdPartyNo = callbackData.get("thirdPartyNo");
            String statusStr = callbackData.get("status");
            
            if (!StringUtils.hasText(paymentNo) || !StringUtils.hasText(statusStr)) {
                log.warn("回调参数不完整: {}", callbackData);
                return ResponseEntity.badRequest().body("INVALID_PARAMS");
            }

            Payment.PaymentStatus status = Payment.PaymentStatus.valueOf(statusStr);
            
            // 处理支付回调
            paymentService.handlePaymentCallback(paymentNo, thirdPartyNo, status, notifyContent);
            
            return ResponseEntity.ok("SUCCESS");

        } catch (Exception e) {
            log.error("处理支付回调异常: {}", e.getMessage(), e);
            return ResponseEntity.badRequest().body("FAILED");
        }
    }

    @GetMapping("/user/list")
    @Operation(summary = "查询用户支付记录")
    @PreAuthorize("hasRole('USER')")
    public ResponseEntity<Map<String, Object>> getUserPayments(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            Authentication authentication) {

        try {
            String userId = authentication.getName();
            Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
            
            Page<Payment> payments = paymentService.getUserPayments(userId, pageable);

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("data", payments.getContent());
            response.put("pagination", Map.of(
                "page", payments.getNumber(),
                "size", payments.getSize(),
                "totalElements", payments.getTotalElements(),
                "totalPages", payments.getTotalPages()
            ));

            return ResponseEntity.ok(response);

        } catch (Exception e) {
            log.error("查询用户支付记录异常: {}", e.getMessage(), e);
            throw new BusinessException("PAYMENT_LIST_ERROR", "查询支付记录失败");
        }
    }

    @GetMapping("/merchant/list")
    @Operation(summary = "查询商家支付记录")
    @PreAuthorize("hasRole('MERCHANT') or hasRole('ADMIN')")
    public ResponseEntity<Map<String, Object>> getMerchantPayments(
            @RequestParam Long merchantId,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            Authentication authentication) {

        try {
            // 权限检查 - 商家只能查询自己的记录
            // 这里应该验证当前用户是否有权限查询该商家的支付记录
            
            Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
            Page<Payment> payments = paymentService.getMerchantPayments(merchantId, pageable);

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("data", payments.getContent());
            response.put("pagination", Map.of(
                "page", payments.getNumber(),
                "size", payments.getSize(),
                "totalElements", payments.getTotalElements(),
                "totalPages", payments.getTotalPages()
            ));

            return ResponseEntity.ok(response);

        } catch (Exception e) {
            log.error("查询商家支付记录异常: {}", e.getMessage(), e);
            throw new BusinessException("PAYMENT_LIST_ERROR", "查询支付记录失败");
        }
    }

    /**
     * 验证创建支付请求
     */
    private void validateCreatePaymentRequest(CreatePaymentRequest request) {
        if (request.getOrderId() == null || request.getOrderId() <= 0) {
            throw new BusinessException("INVALID_ORDER_ID", "订单ID无效");
        }

        if (request.getPaymentMethod() == null) {
            throw new BusinessException("INVALID_PAYMENT_METHOD", "支付方式不能为空");
        }
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        
        return ip != null ? ip : "unknown";
    }

    /**
     * 验证回调IP是否合法
     */
    private boolean isValidCallbackIp(String clientIp, String channel) {
        // 实际应用中应该维护支付平台的IP白名单
        // 这里为了演示简化处理
        return securityUtils.isValidIpAddress(clientIp);
    }

    /**
     * 解析回调内容
     */
    private Map<String, String> parseCallbackContent(String notifyContent, String channel) {
        Map<String, String> result = new HashMap<>();
        
        // 这里应该根据具体支付渠道的回调格式解析
        // 为了演示，我们简化处理
        try {
            // 假设是JSON格式
            String[] pairs = notifyContent.split("&");
            for (String pair : pairs) {
                String[] kv = pair.split("=");
                if (kv.length == 2) {
                    result.put(kv[0], kv[1]);
                }
            }
        } catch (Exception e) {
            log.warn("解析回调内容失败: {}", e.getMessage());
        }
        
        return result;
    }

    /**
     * 创建支付请求DTO
     */
    @Data
    public static class CreatePaymentRequest {
        @NotNull(message = "订单ID不能为空")
        @Positive(message = "订单ID必须为正数")
        private Long orderId;

        @NotNull(message = "支付方式不能为空")
        private Payment.PaymentMethod paymentMethod;
    }
}
